package org.msb.accentis.data;

import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set;

import org.msb.accentis.data.pojo.BaseObject;

public class ObjectNotifier {

	private Set<IObjectListener> listeners = new HashSet<IObjectListener>();

	public void addListener(IObjectListener listener) {
		synchronized (listeners) {
			listeners.add(listener);
		}
	}

	public void removeListener(IObjectListener listener) {
		synchronized (listeners) {
			listeners.remove(listener);
		}
	}

	public void objectCreated(BaseObject object) {
		synchronized (listeners) {
			for (IObjectListener listener : listeners)
				if (listener.listensToClass(object.getClass()))
					notifyObjectCreatedOnSwingThread(listener, object);
		}
	}

	public void objectDeleted(BaseObject object) {
		synchronized (listeners) {
			for (IObjectListener listener : listeners)
				if (listener.listensToClass(object.getClass()))
					notifyObjectRemovedOnSwingThread(listener, object);
		}
	}

	public void objectRefreshed(BaseObject object) {
		synchronized (listeners) {
			for (IObjectListener listener : listeners)
				if (listener.listensToClass(object.getClass()))
					notifyObjectRefreshedOnSwingThread(listener, object);
		}
	}

	public void objectSaved(BaseObject object) {
		synchronized (listeners) {
			for (IObjectListener listener : listeners)
				if (listener.listensToClass(object.getClass()))
					notifyObjectSavedOnSwingThread(listener, object);
		}
	}

	Set<IObjectListener> getListeners() {
		return listeners;
	}

	private void notifyObjectCreatedOnSwingThread(final IObjectListener listener, final BaseObject object) {
		if (EventQueue.isDispatchThread())
			listener.objectCreated(object);
		else
			try {
				EventQueue.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						listener.objectCreated(object);
					}
				});
			} catch (InvocationTargetException | InterruptedException e) {
				e.printStackTrace();
			}
	}
	
	private void notifyObjectRemovedOnSwingThread(final IObjectListener listener, final BaseObject object) {
		if (EventQueue.isDispatchThread())
			listener.objectRemoved(object);
		else
			try {
				EventQueue.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						listener.objectRemoved(object);
					}
				}); 
			} catch (InvocationTargetException | InterruptedException e) {
				e.printStackTrace();
			}
	}

	private void notifyObjectRefreshedOnSwingThread(final IObjectListener listener, final BaseObject object) {
		if (EventQueue.isDispatchThread())
			listener.objectRefreshed(object);
		else
			try {
				EventQueue.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						listener.objectRefreshed(object);
					}
				}); 
			} catch (InvocationTargetException | InterruptedException e) {
				e.printStackTrace();
			}
	}

	private void notifyObjectSavedOnSwingThread(final IObjectListener listener, final BaseObject object) {
		if (EventQueue.isDispatchThread())
			listener.objectSaved(object);
		else
			try {
				EventQueue.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						listener.objectSaved(object);
					}
				}); 
			} catch (InvocationTargetException | InterruptedException e) {
				e.printStackTrace();
			}
	}
}